package com.quectel.cms.controller.propertybill;


import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.business.common.mobileuser.MobileUserMsgBusiness;
import com.quectel.business.common.propertybill.PropertyBillBusiness;
import com.quectel.cms.controller.BaseController;
import com.quectel.cms.util.SessionHolder;
import com.quectel.constant.core.propertybill.PropertyBillConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.global.annotation.RequirePermissions;
import com.quectel.core.module.household.service.HouseholdRoomService;
import com.quectel.core.module.mobileuser.service.MobileUserService;
import com.quectel.core.module.propertybill.dto.PropertyBillDto;
import com.quectel.core.module.propertybill.service.*;
import com.quectel.core.module.propertybill.vo.PropertyBillAmountVo;
import com.quectel.core.module.village.service.VillageRoomService;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.Page;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import com.quectel.util.redis.RedisUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.locks.Lock;

/**
 * @author zhangheng
 * @email nolan.zhang@quectel.com
 * @date 2023/03/31 16:28
 */
@RestController
@RequestMapping("propertyBill")
@Tag(name = "PropertyBillController", description = "物业收费账单表相关api")
public class PropertyBillController extends BaseController {

    @DubboReference
    private PropertyBillService propertyBillService;
    @DubboReference
    private VillageRoomService villageRoomService;
    @DubboReference
    private PropertyChargeableListService propertyChargeableListService;
    @DubboReference
    private PropertyChargeableListItemBindingService propertyChargeableListItemBindingService;
    @DubboReference
    private PropertyChargeableListDueDateService propertyChargeableListDueDateService;

    @DubboReference
    private PropertyChargeableItemService propertyChargeableItemService;

    @DubboReference
    private HouseholdRoomService householdRoomService;

    @DubboReference
    private MobileUserService mobileUserService;

    @Autowired
    private PropertyBillActivityService propertyBillActivityService;

    @Autowired
    private PropertyBillBusiness propertyBillBusiness;
    @Autowired
    private MobileUserMsgBusiness mobileUserMsgBusiness;

    private static final String PROPERTY_BILL_LOCK = "PROPERTY_BILL_LOCK:";
    private static final String ROOM_NAME_FLAG = "roomName";


    /**
     * 根据账单详情重新更新订单信息
     *
     * @return
     */
    @GetMapping("oneClickCall")
    @RequirePermissions(values = "propertyBill:edit")
    @Operation(summary = "一键催缴")
    public Response<Object> oneClickCall(
            @Parameter(description = "小区id") @RequestParam Long villageId,
            @Parameter(description = "楼栋id") @RequestParam(required = false) Long buildingId,
            @Parameter(description = "楼层id") @RequestParam(required = false) Long floorId,
            @Parameter(description = "房间id") @RequestParam(required = false) Long roomId,
            @Parameter(description = "渠道arr") @RequestParam String publishChannel

    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        super.fillAuthorityData(request.getParams());

        List<Byte> byteList = JacksonUtils.parseArray(publishChannel, Byte.class);
        //查询满足条件的账单
        //支付状态为未支付
        request.put(LambdaUtil.getFieldName(PropertyBillDto::getTenantId), SessionHolder.getSysUser().getTenantId());
        request.put(LambdaUtil.getFieldName(PropertyBillDto::getVillageId), villageId);
        request.put(LambdaUtil.getFieldName(PropertyBillDto::getBuildingId), buildingId);
        request.put(LambdaUtil.getFieldName(PropertyBillDto::getFloorId), floorId);
        request.put(LambdaUtil.getFieldName(PropertyBillDto::getRoomId), roomId);
        request.put(SystemConstants.PAY_STATUSES, PropertyBillConstants.NOT_PAY_STATUS_LIST);
        //逾期账单
        request.put(LambdaUtil.getFieldName(PropertyBillDto::getOverdueStatus), SystemConstants.NORMAL);
        List<PropertyBillDto> propertyBillDtos = propertyBillService.queryList(request.getParams());

        for (PropertyBillDto propertyBillDto : propertyBillDtos) {
            propertyBillBusiness.sendPropertyBillMsg(propertyBillDto.getId(), byteList, PropertyBillConstants.MsgType.OVERDUE.getType());

        }
        //推送消息通知

        return Response.ok();
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @PostMapping("confirmActivity")
    @RequirePermissions(values = "propertyBill:edit")
    @Operation(summary = "赠品确认")
    public Response<Object> confirmActivity(@RequestBody Long[] ids) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);

        for (Long id : ids) {

            params.remove(SystemConstants.ENTITY_ID_FLAG);
            params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));

            if (propertyBillService.queryTotal(params) <= 0) {
                return Response.error(SystemConstants.ILLEGAL_MSG);
            }

            PropertyBillDto propertyBillDto = propertyBillService.selectCacheById(id);
            //账单不存在或者未付款则不可以确认
            if (propertyBillDto == null || !PropertyBillConstants.PayStatus.PAY_SUCCESS.getStatusValue().equals(propertyBillDto.getPayStatus())) {
                return Response.error(SystemConstants.ILLEGAL_MSG);
            }
            PropertyBillAmountVo propertyBillAmount = propertyBillDto.getPropertyBillAmount();

            //是否有赠品
            if (propertyBillAmount != null && CollectionUtils.isEmpty(propertyBillAmount.getGiftList())) {
                return Response.error("该笔账单没有赠品可以领取");
            }

            if (SystemConstants.YES.equals(propertyBillDto.getGiftFlag())) {
                return Response.error("已确认领取赠品，不可重复确认");
            }
            propertyBillService.confirmActivity(id);
        }

        return Response.ok();
    }


    /**
     * 根据账单详情重新更新订单信息
     *
     * @param dto
     * @return
     */
    @PostMapping("updateBillInfo")
    @RequirePermissions(values = "propertyBill:edit")
    @Operation(summary = "更新账单信息")
    public Response<Object> updateBillInfo(@RequestBody @Validated PropertyBillDto dto) {
        if (dto.getPropertyBillAmount() == null) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }
        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(dto.getId()));
        if (propertyBillService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        PropertyBillDto propertyBillDto = propertyBillService.selectById(dto.getId());

        //未支付账单才可以修改
        if (PropertyBillConstants.PayStatus.PAY_SUCCESS.getStatusValue().equals(propertyBillDto.getPayStatus())) {
            return Response.error("未支付账单才可以编辑修改");
        }
        //重新计算订单信息
        PropertyBillAmountVo editedPropertyBill = propertyBillBusiness.getEditedPropertyBill(dto.getPropertyBillAmount());
        //更新PropertyBill
        PropertyBillDto newPropertyBillDto = propertyBillBusiness.genBillByPropertyBillAmountVo(editedPropertyBill);
        propertyBillDto.setTotalAmount(newPropertyBillDto.getTotalAmount());
        propertyBillDto.setItemAmount(newPropertyBillDto.getItemAmount());
        propertyBillDto.setDiscountAmount(newPropertyBillDto.getDiscountAmount());
        propertyBillDto.setOverdueAmount(newPropertyBillDto.getOverdueAmount());
        propertyBillDto.setOverdueDate(newPropertyBillDto.getOverdueDate());
        propertyBillDto.setOverdueDays(newPropertyBillDto.getOverdueDays());
        propertyBillDto.setStartDate(newPropertyBillDto.getStartDate());
        propertyBillDto.setEndDate(newPropertyBillDto.getEndDate());
        propertyBillDto.setUpdateTime(new Date());
        propertyBillDto.setPropertyBillAmount(editedPropertyBill);

        Lock spinLock = RedisUtils.getSpinLock(PROPERTY_BILL_LOCK + propertyBillDto.getId());
        spinLock.lock();
        try {
            //保存
            propertyBillService.saveOrUpdateWithAmountVO(propertyBillDto);
            return Response.ok();
        } catch (Exception e) {
            logger.error("auditReq", e);
        } finally {
            spinLock.unlock();
        }

        return Response.ok();
    }


    /**
     * 确认账单,后台管理员手动确认账单,标记为已支付
     *
     * @param dto
     * @return
     */
    @PostMapping("confirmBillInfo")
    @RequirePermissions(values = "propertyBill:edit")
    @Operation(summary = "更新账单信息")
    public Response<Object> confirmBillInfo(@RequestBody @Validated PropertyBillDto dto) {
        if (dto.getPropertyBillAmount() == null) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }
        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(dto.getId()));
        if (propertyBillService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        PropertyBillDto propertyBillDto = propertyBillService.selectById(dto.getId());

        //未支付账单才可以修改
        if (PropertyBillConstants.PayStatus.PAY_SUCCESS.getStatusValue().equals(propertyBillDto.getPayStatus())) {
            return Response.error("未支付账单才可以编辑修改");
        }
        //重新计算订单信息
        PropertyBillAmountVo editedPropertyBill = propertyBillBusiness.getEditedPropertyBill(dto.getPropertyBillAmount());
        //更新PropertyBill
        PropertyBillDto newPropertyBillDto = propertyBillBusiness.genBillByPropertyBillAmountVo(editedPropertyBill);
        propertyBillDto.setTotalAmount(newPropertyBillDto.getTotalAmount());
        propertyBillDto.setItemAmount(newPropertyBillDto.getItemAmount());
        propertyBillDto.setDiscountAmount(newPropertyBillDto.getDiscountAmount());
        propertyBillDto.setOverdueAmount(newPropertyBillDto.getOverdueAmount());
        propertyBillDto.setOverdueDate(newPropertyBillDto.getOverdueDate());
        propertyBillDto.setOverdueDays(newPropertyBillDto.getOverdueDays());
        propertyBillDto.setStartDate(newPropertyBillDto.getStartDate());
        propertyBillDto.setEndDate(newPropertyBillDto.getEndDate());
        //赠品相关

        if (newPropertyBillDto.getPropertyBillAmount() != null && newPropertyBillDto.getPropertyBillAmount().getGiftList() != null) {
            propertyBillDto.setGiftNum(newPropertyBillDto.getPropertyBillAmount().getGiftList().size());
            propertyBillDto.setGiftFlag(SystemConstants.NO);
        } else {
            propertyBillDto.setGiftNum(0);
            //如果没有赠品则标记为已领取
            propertyBillDto.setGiftFlag(SystemConstants.YES);
        }


        propertyBillDto.setPropertyBillAmount(editedPropertyBill);
        //更新支付信息
        propertyBillDto.setPayAmount(newPropertyBillDto.getTotalAmount());

        Lock spinLock = RedisUtils.getSpinLock(PROPERTY_BILL_LOCK + propertyBillDto.getId());
        spinLock.lock();
        try {
            //保存
            propertyBillService.saveOrUpdateWithAmountVO(propertyBillDto);
            //支付成功
            propertyBillDto.setPayStatus(PropertyBillConstants.PayStatus.PAY_SUCCESS.getStatusValue());
            propertyBillDto.setPayTime(new Date());
            propertyBillDto.setUpdateTime(new Date());
            propertyBillService.billPaySuccessUpdateDueDate(propertyBillDto);

            return Response.ok();
        } catch (Exception e) {
            logger.error("auditReq", e);
        } finally {
            spinLock.unlock();
        }

        return Response.ok();
    }

    /**
     * 编辑收费项目和活动,生成新的账单详情
     *
     * @param propertyBillAmount
     * @return
     */
    @PostMapping("getEditedPropertyBill")
    @RequirePermissions(values = "propertyBill:edit")
    @Operation(summary = "获取编辑后的账单信息")
    public Response<PropertyBillAmountVo> getEditedPropertyBill(@RequestBody @Validated PropertyBillAmountVo propertyBillAmount) {
        propertyBillBusiness.getEditedPropertyBill(propertyBillAmount);
        return Response.<PropertyBillAmountVo>ok().wrap(propertyBillBusiness.getEditedPropertyBill(propertyBillAmount));
    }

    /**
     * 获取账单详情
     *
     * @param id
     * @return
     */
    @GetMapping("getPropertyBillAmount")
    @RequirePermissions(values = "propertyBill:info")
    @Operation(summary = "获取账单详情")
    public Response<PropertyBillAmountVo> getPropertyBillAmount(
            @Parameter(description = "账单id") @RequestParam Long id
    ) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (propertyBillService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }
        PropertyBillDto dbDto = propertyBillService.selectById(id);

        //返回已经保存的账单详情
        if (dbDto.getPropertyBillAmount() != null) {
            return Response.<PropertyBillAmountVo>ok().wrap(dbDto.getPropertyBillAmount());
        }

        PropertyBillAmountVo propertyBillAmountVo = propertyBillBusiness.generatePropertyBill(dbDto.getChargeableListId(), dbDto.getRoomId(), dbDto.getStartDate(), Boolean.TRUE);
        return Response.<PropertyBillAmountVo>ok().wrap(propertyBillAmountVo);
    }

    /**
     * 分页查询
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("list")
    @RequirePermissions(values = "propertyBill:list")
    @Operation(summary = "分页列表")
    public Response<Page<PropertyBillDto>> list(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize
    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        super.fillAuthorityData(request.getParams());
        int total = propertyBillService.queryTotal(request.getParams());

        List<PropertyBillDto> list = null;
        if (total > 0) {
            list = propertyBillService.queryList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        Page<PropertyBillDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<PropertyBillDto>>ok().wrap(page);
    }

    /**
     * 编辑查询反显
     *
     * @param id
     * @return
     */
    @GetMapping("infoForEdit/{id}")
    @RequirePermissions(values = "propertyBill:edit")
    @Operation(summary = "查询单条记录")
    public Response<PropertyBillDto> infoForEdit(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (propertyBillService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        PropertyBillDto propertyBillDto = propertyBillService.selectById(id);

        return Response.<PropertyBillDto>ok().wrap(propertyBillDto);
    }

    /**
     * 详情
     *
     * @param id
     * @return
     */
    @GetMapping("info/{id}")
    @RequirePermissions(values = "propertyBill:info")
    @Operation(summary = "查询单条记录")
    public Response<PropertyBillDto> info(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (propertyBillService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        PropertyBillDto propertyBillDto = propertyBillService.selectById(id);

        return Response.<PropertyBillDto>ok().wrap(propertyBillDto);
    }

    /**
     * 保存
     *
     * @param propertyBillDto
     * @return
     */
    @PostMapping("save")
    @RequirePermissions(values = "propertyBill:edit")
    @Operation(summary = "保存单条记录")
    public Response<Object> save(@RequestBody @Validated PropertyBillDto propertyBillDto) {

        //填充基础数据
        fillSaveCommonData(propertyBillDto);

        propertyBillService.save(propertyBillDto);

        return Response.ok();
    }


    /**
     * 修改
     *
     * @param propertyBillDto
     * @return
     */
    @PostMapping("update")
    @RequirePermissions(values = "propertyBill:edit")
    @Operation(summary = "修改单条记录")
    public Response<Object> update(@RequestBody @Validated PropertyBillDto propertyBillDto) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(propertyBillDto.getId()));
        if (propertyBillService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }
        //填充基础数据
        fillEditCommonData(propertyBillDto);

        propertyBillService.updateById(propertyBillDto);

        return Response.ok();
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @PostMapping("delete")
    @RequirePermissions(values = "propertyBill:delete")
    @Operation(summary = "批量删除记录")
    public Response<Object> delete(@RequestBody Long[] ids) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);

        for (Long id : ids) {

            params.remove(SystemConstants.ENTITY_ID_FLAG);
            params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));

            if (propertyBillService.queryTotal(params) <= 0) {
                return Response.error(SystemConstants.ILLEGAL_MSG);
            }
            PropertyBillDto propertyBillDto = propertyBillService.selectById(id);
            //未支付的账单才可以删除
            if (PropertyBillConstants.PayStatus.PAY_SUCCESS.getStatusValue().equals(propertyBillDto.getPayStatus())) {
                return Response.error("支付或者退款订单无法删除");
            }
        }

        propertyBillService.deleteBatch(ids);

        return Response.ok();
    }
}
